package com.shrcl.engineerprocess.domain.impl;

import com.google.common.base.Objects;
import com.shrcl.engineerprocess.domain.Engineer;
import com.shrcl.engineerprocess.domain.EngineerTraining;
import com.shrcl.engineerprocess.domain.EngineerTrainingStatus;
import com.shrcl.engineerprocess.domain.TrainingNotification;
import com.shrcl.engineerprocess.domain.TrainingNotificationDAO;
import com.shrcl.engineerprocess.domain.impl.EngineerImpl;
import com.shrcl.engineerprocess.domain.proxy.EngineerTrainingProxy;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import edu.fudan.mylang.pf.ISystemDateTimeService;
import edu.fudan.mylang.utils.DateUtil;
import java.util.Collection;
import java.util.Date;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("ENGINEERTRAINING_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "engineertraining")
public class EngineerTrainingImpl extends BaseModelObject implements EngineerTraining {
  public EngineerTrainingImpl() {
    super();
  }
  
  private EngineerTrainingStatus Status;
  
  public EngineerTrainingStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    
    Status=EngineerTrainingStatus.created;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerTrainingEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _notifyTrainee() {
    
    this.performTrainingNotification();
  }
  
  public void notifyTrainee() {
    if(Status==EngineerTrainingStatus.created||Status==EngineerTrainingStatus.firstNotified||Status==EngineerTrainingStatus.secondNotified){
    	_notifyTrainee();
    	getModelObjectLogService().createLog(this,"Status","notifyTrainee");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerTrainingEventsManager.class).fireNotifyTrainee(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _firstNotifyTimer() {
    
    boolean _notEquals = (!Objects.equal(this.firstRemindAdvancedDay, null));
    if (_notEquals) {
      BeanFactory _beanFactory = this.getBeanFactory();
      final ISystemDateTimeService dateTimeService = _beanFactory.<ISystemDateTimeService>getBean(ISystemDateTimeService.class);
      int _minus = (-this.firstRemindAdvancedDay);
      final Date notifyDate = DateUtil.addDays(this.startdate, _minus);
      boolean _and = false;
      Date _day = dateTimeService.today();
      boolean _lessThan = (_day.compareTo(notifyDate) < 0);
      if (!_lessThan) {
        _and = false;
      } else {
        Date _day_1 = dateTimeService.today();
        Date _addDays = DateUtil.addDays(_day_1, 1);
        boolean _lessThan_1 = (notifyDate.compareTo(_addDays) < 0);
        _and = (_lessThan && _lessThan_1);
      }
      if (_and) {
        this.performTrainingNotification();
        Status=EngineerTrainingStatus.firstNotified;
      }
    }
  }
  
  public void firstNotifyTimer() {
    if(Status==EngineerTrainingStatus.created){
    	_firstNotifyTimer();
    	getModelObjectLogService().createLog(this,"Status","firstNotifyTimer");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerTrainingEventsManager.class).fireFirstNotifyTimer(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _secondNotifyTimer() {
    
    boolean _notEquals = (!Objects.equal(this.secondRemindAdvancedDay, null));
    if (_notEquals) {
      BeanFactory _beanFactory = this.getBeanFactory();
      final ISystemDateTimeService dateTimeService = _beanFactory.<ISystemDateTimeService>getBean(ISystemDateTimeService.class);
      int _minus = (-this.secondRemindAdvancedDay);
      final Date notifyDate = DateUtil.addDays(this.startdate, _minus);
      boolean _and = false;
      Date _day = dateTimeService.today();
      boolean _lessThan = (_day.compareTo(notifyDate) < 0);
      if (!_lessThan) {
        _and = false;
      } else {
        Date _day_1 = dateTimeService.today();
        Date _addDays = DateUtil.addDays(_day_1, 1);
        boolean _lessThan_1 = (notifyDate.compareTo(_addDays) < 0);
        _and = (_lessThan && _lessThan_1);
      }
      if (_and) {
        this.performTrainingNotification();
        Status=EngineerTrainingStatus.secondNotified;
      }
    }
  }
  
  public void secondNotifyTimer() {
    if(Status==EngineerTrainingStatus.firstNotified){
    	_secondNotifyTimer();
    	getModelObjectLogService().createLog(this,"Status","secondNotifyTimer");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerTrainingEventsManager.class).fireSecondNotifyTimer(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _finish() {
    
    Status=EngineerTrainingStatus.finished;
  }
  
  public void finish() {
    if(Status==EngineerTrainingStatus.secondNotified){
    	_finish();
    	getModelObjectLogService().createLog(this,"Status","finish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerTrainingEventsManager.class).fireFinish(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isCreated() {
    return com.shrcl.engineerprocess.domain.EngineerTrainingStatus.created==Status;
  }
  
  public Boolean isFirstNotified() {
    return com.shrcl.engineerprocess.domain.EngineerTrainingStatus.firstNotified==Status;
  }
  
  public Boolean isSecondNotified() {
    return com.shrcl.engineerprocess.domain.EngineerTrainingStatus.secondNotified==Status;
  }
  
  public Boolean isFinished() {
    return com.shrcl.engineerprocess.domain.EngineerTrainingStatus.finished==Status;
  }
  
  private String trainer;
  
  public String getTrainer() {
    return this.trainer;
  }
  
  public EngineerTraining setTrainer(final String trainer) {
    this.trainer = trainer;
    return this;			
    
  }
  
  private String name;
  
  public String getName() {
    return this.name;
  }
  
  public EngineerTraining setName(final String name) {
    this.name = name;
    return this;			
    
  }
  
  private String topic;
  
  public String getTopic() {
    return this.topic;
  }
  
  public EngineerTraining setTopic(final String topic) {
    this.topic = topic;
    return this;			
    
  }
  
  private String location;
  
  public String getLocation() {
    return this.location;
  }
  
  public EngineerTraining setLocation(final String location) {
    this.location = location;
    return this;			
    
  }
  
  private Date startdate;
  
  public Date getStartdate() {
    return this.startdate;
  }
  
  public EngineerTraining setStartdate(final Date startdate) {
    this.startdate = startdate;
    return this;			
    
  }
  
  private Date enddate;
  
  public Date getEnddate() {
    return this.enddate;
  }
  
  public EngineerTraining setEnddate(final Date enddate) {
    this.enddate = enddate;
    return this;			
    
  }
  
  @ManyToMany(targetEntity = EngineerImpl.class)
  @JoinTable(name = "m2m_engineertraining_trainees", joinColumns = @JoinColumn(name = "engineertraining_id") , inverseJoinColumns = @JoinColumn(name = "engineer_inv_id") )
  private Collection<Engineer> trainees = new java.util.ArrayList<com.shrcl.engineerprocess.domain.Engineer>();;
  
  public Collection<Engineer> getTrainees() {
    return this.trainees;
  }
  
  public EngineerTraining setTrainees(final Iterable<Engineer> trainees) {
    removeAllTrainees();
    for(Engineer ca : trainees){
    	addtoTrainees(ca);
    }
    return this;		
    
  }
  
  public EngineerTraining addtoTrainees(final Engineer engineer) {
    this.trainees.add(engineer);
    return this;
    
  }
  
  public EngineerTraining removeAllTrainees() {
    this.trainees.clear();
    return this;	
    
  }
  
  public EngineerTraining removeFromTrainees(final Engineer engineer) {
    this.trainees.remove(engineer);
    return this;
    
  }
  
  private Integer firstRemindAdvancedDay;
  
  public Integer getFirstRemindAdvancedDay() {
    return this.firstRemindAdvancedDay;
  }
  
  public EngineerTraining setFirstRemindAdvancedDay(final Integer firstRemindAdvancedDay) {
    this.firstRemindAdvancedDay = firstRemindAdvancedDay;
    return this;			
    
  }
  
  private Integer secondRemindAdvancedDay;
  
  public Integer getSecondRemindAdvancedDay() {
    return this.secondRemindAdvancedDay;
  }
  
  public EngineerTraining setSecondRemindAdvancedDay(final Integer secondRemindAdvancedDay) {
    this.secondRemindAdvancedDay = secondRemindAdvancedDay;
    return this;			
    
  }
  
  public void performTrainingNotification() {
    BeanFactory _beanFactory = this.getBeanFactory();
    final TrainingNotificationDAO trainingNotificationDAO = _beanFactory.<TrainingNotificationDAO>getBean(TrainingNotificationDAO.class);
    final Procedure1<Engineer> _function = new Procedure1<Engineer>() {
        public void apply(final Engineer e) {
          final Procedure1<TrainingNotification> _function = new Procedure1<TrainingNotification>() {
              public void apply(final TrainingNotification it) {
                it.setEngineerTraining(EngineerTrainingImpl.this);
                it.setToEngineer(e);
              }
            };
          TrainingNotification _create = trainingNotificationDAO.create(_function);
          final Procedure1<TrainingNotification> _function_1 = new Procedure1<TrainingNotification>() {
              public void apply(final TrainingNotification it) {
                it.performNotify();
              }
            };
          ObjectExtensions.<TrainingNotification>operator_doubleArrow(_create, _function_1);
        }
      };
    IterableExtensions.<Engineer>forEach(this.trainees, _function);
  }
  
  public static EngineerTraining create(final IObjectFactory objectFactory) {
    com.shrcl.engineerprocess.domain.EngineerTraining engineerTraining = new com.shrcl.engineerprocess.domain.impl.EngineerTrainingImpl(
    );
    objectFactory.create(engineerTraining);
    return engineerTraining;			
    
  }
  
  public static EngineerTraining createEngineerTrainingImpl(final IObjectFactory objectFactory, final Procedure1<EngineerTraining> init) {
    com.shrcl.engineerprocess.domain.EngineerTraining engineerTraining = new com.shrcl.engineerprocess.domain.impl.EngineerTrainingImpl(
    );
    objectFactory.create(engineerTraining);
    init.apply(engineerTraining);
    
    return engineerTraining;			
    
  }
  
  public EngineerTrainingProxy toProxy() {
    com.shrcl.engineerprocess.domain.proxy.EngineerTrainingProxy proxy = new com.shrcl.engineerprocess.domain.proxy.EngineerTrainingProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
